/**
 ********************************************************************
 * @author roocket
 * @file    server.c
 * @version V0.0.0
 * @date    2024/3/22
 * @brief   This file is to indicate server functions. 
 * @attention Code file rules:
 * rule: file encoding use UTF8;
 * rule: max line length 120 characters;
 * rule: line separator \r\n;
 * rule: use clion auto code format tool.
 */

#ifndef _SERVER_H_
#define _SERVER_H_

#include "socket.h"
#include <sys/select.h>
#include <sys/epoll.h>

int server_init_socket(const char *address, const unsigned short port)
{
    return socket_server_init(address, port); 
}

int server_get_data(int fd, void *user)
{
    return socket_get_data(fd, user);
}

int server_set_data(int fd, void *sent, int length)
{
    return socket_set_data(fd, sent, length);
}

static void _epoll_hdl_data(struct epoll_event *ev, struct epoll_event *events, int epoll_fd, int fd, int epoll_num)
{
    int err = -1;
    for (int i = 0; i < epoll_num; i++) {
        if (events[i].data.fd == fd) {
            struct sockaddr_in client_addr;
            socklen_t len = sizeof(struct sockaddr_in);
            int client_fd = accept(fd, (struct sockaddr *)&client_addr, &len);
            if(client_fd == -1) {
                perror("accept");
                continue;
            }

            char ip[32]={0};
            inet_ntop(AF_INET, &(client_addr.sin_addr.s_addr), ip, sizeof(ip));
            printf("a new client connected! ip:%s  port:%d\n", ip, ntohs(client_addr.sin_port));

            ev->data.fd = client_fd;
            ev->events = EPOLLIN;
            epoll_ctl(epoll_fd, EPOLL_CTL_ADD, client_fd, ev);
        } else {
            if(events[i].events & EPOLLOUT)
                continue;

            char buf[1024]={0};
            struct sockaddr_in peerAddr;
            unsigned int peerLen;
            char ip[32]={0};

            inet_ntop(AF_INET, &(peerAddr.sin_addr), ip, sizeof(ip));
            getpeername(events[i].data.fd, (struct sockaddr *)&peerAddr, &peerLen); 
            int data = read(events[i].data.fd, buf, sizeof(buf));
            if (data == 0) {
                printf("%s(%d) closed connection......\n", ip, ntohs(peerAddr.sin_port));
                close(events[i].data.fd);
                epoll_ctl(epoll_fd, EPOLL_CTL_DEL, events[i].data.fd, NULL);
            } else {
                if(data == -1) {
                    perror("read");
                } else {
                    printf("%s:%d say: %s\n",ip , ntohs(peerAddr.sin_port), buf);
                    err = write(events[i].data.fd, buf, strlen(buf) + 1);
                    if (-1 == err)
                        perror("write");
                }
            }
        }
    }
}

int server_epoll_handle_data(int fd)
{
    int epoll_fd = -1;
    int num = -1;

    epoll_fd = epoll_create(1000);
    if(-1 == epoll_fd)
        perror("epoll_create");

    struct epoll_event ev;
    ev.events = EPOLLIN;
    ev.data.fd = fd;
    epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev);

    struct epoll_event events[1024];
    while(1)
    {
        num = epoll_wait(epoll_fd, events, sizeof(events)/sizeof(events[0]), -1);
        if (-1 == num)
            continue;

        _epoll_hdl_data(&ev, events, epoll_fd, fd, num);
    }
}


void server_del_socket(int fd)
{
    return socket_del(fd);
}

#endif /* _SERVER_H_ */
